#include <errno.h>
#include <assert.h>
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <infiniband/verbs.h>
//#include "configure.h"

#include "queue.h"

#include "mem_pool.h"
//#include "dbg.h"
#include "memory_internal.h"

static int lich_rdma_mr_map_notify(void *cb_ctx, struct lich_mem_map *map, enum lich_mem_map_notify_action action, 
				void *vaddr, size_t size)
{
	struct ibv_pd *pd = cb_ctx;
	struct ibv_mr *mr;
	int rc;

	switch (action) {
	case LICH_MEM_MAP_NOTIFY_REGISTER:
		mr = ibv_reg_mr(pd, vaddr, size,
				IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ | IBV_ACCESS_REMOTE_WRITE);
		if (mr == NULL) {
			//DERROR("ibv_reg_mr() failed\n");
			return -EFAULT;
		} else {
			rc = lich_mem_map_set_translation(map, (uint64_t)vaddr, size, (uint64_t)mr);
		}
		break;
	case LICH_MEM_MAP_NOTIFY_UNREGISTER:
		mr = (struct ibv_mr *)lich_mem_map_translate(map, (uint64_t)vaddr);
		rc = lich_mem_map_clear_translation(map, (uint64_t)vaddr, size);
		if (mr) {
			ibv_dereg_mr(mr);
		}
		break;
	default:
		assert(0);
	}

	return rc;
}

static struct lich_mem_map * lich_rdma_register_mem(struct ibv_pd *pd)
{
	struct lich_mem_map *mr_map;

	// TODO: look up existing mem map registration for this pd

	mr_map = lich_mem_map_alloc((uint64_t)NULL, lich_rdma_mr_map_notify, pd);
	if (mr_map == NULL) {
		//DERROR("lich_mem_map_alloc() failed\n");
		return NULL;
	}

	return mr_map;
}

static void lich_rdma_unregister_mem(struct lich_mem_map ** mr_map)
{
	lich_mem_map_free(mr_map);
}